package br.uff.probabilidade.modelo.tabuleiro;

import java.awt.Color;
import java.awt.Point;
import java.util.Random;
import java.util.Vector;

import br.uff.probabilidade.modelo.Conjunto;
import br.uff.probabilidade.modelo.Evento;
import br.uff.probabilidade.modelo.Legenda;
import br.uff.probabilidade.modelo.Operacao;

public class Grupamento {	
	public static final int OPERACAO_UNIAO = 0;
	public static final int OPERACAO_INTERSECAO = 1;
	public static final int OPERACAO_DIFERENCA = 2;
	public static final int OPERACAO_DIFERENCA_REVERSO = 3;
	
	private static final String CODIFICA_COMPLEMENTO = "|";
	private static final String CODIFICA_UNIAO = "v";
	private static final String CODIFICA_INTERSECAO = "^";
	private static final String CODIFICA_DIFERENCA = "-";
	
	Vector eventos = new Vector();
	Vector operacoes = new Vector();
	
	public void addEvento(Evento evento){	
		evento.getConjunto().setNome(Nivel.NOMES_EVENTO[this.eventos.size()]);
		this.eventos.add(evento);
	}
	public Evento getEventoAt(int i){
		return (Evento)this.eventos.get(i);
	}
	public void addOperacao(Operacao operacao){
		this.operacoes.add(operacao);
	}	
	
	public Operacao getOperacaoAt(int i){
		return (Operacao)this.operacoes.get(i);
	}
	
	public Operacao sorteiaOperacao(){
		int sorteio = new Random().nextInt(this.operacoes.size());
		return this.getOperacaoAt(sorteio);
	}
	
	public boolean pertence(Evento evento){
		for(int i=0;i<eventos.size();i++){
			if(this.getEventoAt(i).getLegenda().getDescricao().equals(evento.getLegenda().getDescricao()))
				return true;
		}
		return false;
	}
	
	public int qntEventos(){
		return this.eventos.size();
	}
	
	private String descricaoOperacao(int operacao){
		switch (operacao) {
		case OPERACAO_UNIAO:
			return "ou";			
		case OPERACAO_INTERSECAO:
			return "e";
		case OPERACAO_DIFERENCA:
			return "e";
		case OPERACAO_DIFERENCA_REVERSO:
			return "e";
		default:
			return "";
		}
	}
	
	private String simboloOperacao(int operacao){
		switch (operacao) {
		case OPERACAO_UNIAO:
			return CODIFICA_UNIAO;			
		case OPERACAO_INTERSECAO:
			return CODIFICA_INTERSECAO;
		case OPERACAO_DIFERENCA:
			return CODIFICA_DIFERENCA;
		case OPERACAO_DIFERENCA_REVERSO:
			return CODIFICA_DIFERENCA;
		default:
			return "";
		}
	}
	
	public void addOperacao(final Evento a,final Evento b,final int operacao){
		
		Legenda legenda = null;
		Conjunto conjunto = null;
		String expressao="";
		if(operacao == OPERACAO_DIFERENCA){
			legenda = new Legenda(a.getLegenda().getDescricao()+ " "+this.descricaoOperacao(operacao)+ b.getLegenda().getDescricaoComplemento(),Color.RED);
			expressao="'"+a.getLegenda().getDescricao()+"'"+CODIFICA_DIFERENCA+"'"+b.getLegenda().getDescricao()+"'";
		}else if(operacao == OPERACAO_DIFERENCA_REVERSO){
			legenda = new Legenda(a.getLegenda().getDescricaoComplemento()+ " "+this.descricaoOperacao(operacao)+" " + b.getLegenda().getDescricao(),Color.RED);
			expressao="'"+b.getLegenda().getDescricao()+"'"+CODIFICA_DIFERENCA+"'"+a.getLegenda().getDescricao()+"'";
		}else{
			legenda = new Legenda(a.getLegenda().getDescricao()+ " "+this.descricaoOperacao(operacao)+" " + b.getLegenda().getDescricao(),Color.RED);		
			expressao="'"+a.getLegenda().getDescricao()+"'"+this.simboloOperacao(operacao)+"'"+b.getLegenda().getDescricao()+"'";
			
		}
    	conjunto = new Conjunto('X');
    	    	
    	    	
    	this.addOperacao(new Operacao(legenda,conjunto,expressao){
    		public boolean isValido(Point coordenada) {
    			if(operacao==OPERACAO_INTERSECAO){
	    			return a.isValido(coordenada) &&
	    			b.isValido(coordenada);
    			}
    			if(operacao==OPERACAO_UNIAO){
	    			return a.isValido(coordenada) ||
	    			b.isValido(coordenada);
    			}
    			
    			if(operacao==OPERACAO_DIFERENCA){
	    			return a.isValido(coordenada) &&
	    			!b.isValido(coordenada);
    			}
    			
    			if(operacao==OPERACAO_DIFERENCA_REVERSO){
	    			return !a.isValido(coordenada) &&
	    			b.isValido(coordenada);
    			}
    			return false;
			}
    		
    	});  
	}
	
	public void addOperacao(final boolean complementoA,final Evento a,final int operacaoAB,final boolean complementoB, final Evento b, final int operacaoBC,final boolean complementoC ,final Evento c,final int precedencia){
		
		Legenda legenda = null;
		Conjunto conjunto = null;
		
		String descricaoA=a.getLegenda().getDescricao(),descricaoB=b.getLegenda().getDescricao(),descricaoC=c.getLegenda().getDescricao(),compAEx="",compBEx="",compCEx="";
		if(complementoA){
			descricaoA = a.getLegenda().getDescricaoComplemento();
			compAEx = CODIFICA_COMPLEMENTO;
		}
		if(complementoB){
			descricaoB = b.getLegenda().getDescricaoComplemento();
			compBEx = CODIFICA_COMPLEMENTO;
		}
		if(complementoC){
			descricaoC = c.getLegenda().getDescricaoComplemento();
			compCEx = CODIFICA_COMPLEMENTO;
		}
		legenda = new Legenda(descricaoA+ " "+this.simboloOperacao(operacaoAB)+" " + descricaoB+ " "+this.simboloOperacao(operacaoBC)+" " + descricaoC,Color.RED);
		String precedenciaAB1="",precedenciaAB2="",precedenciaBC1="",precedenciaBC2="";
		if(operacaoAB!=operacaoBC){
			if(precedencia==0){
				precedenciaAB1="(";
				precedenciaAB2=")";
			}else{
				precedenciaBC1="(";
				precedenciaBC2=")";
			}				
		}
		
		String expressao = precedenciaAB1+compAEx+"'"+a.getLegenda().getDescricao()+"'"+simboloOperacao(operacaoAB)+compBEx+precedenciaBC1+"'"+b.getLegenda().getDescricao()+"'"+precedenciaAB2+simboloOperacao(operacaoBC)+compCEx+"'"+c.getLegenda().getDescricao()+"'"+precedenciaBC2;
		
    	conjunto = new Conjunto('X');
    	
    	
    	    	
    	this.addOperacao(new Operacao(legenda,conjunto,expressao){
    		public boolean isValido(Point coordenada) {
    			boolean validacaoA,validacaoB,validacaoC;
    			if(complementoA)
    				validacaoA = !a.isValido(coordenada);
    			else
    				validacaoA = a.isValido(coordenada);
    			
    			if(complementoB)
    				validacaoB = !b.isValido(coordenada);
    			else
    				validacaoB = b.isValido(coordenada);
    			
    			if(complementoC)
    				validacaoC = !c.isValido(coordenada);
    			else
    				validacaoC = c.isValido(coordenada);
    			
    			boolean acumulador=false;
    			if(precedencia==0){
	    			
	    			if(operacaoAB==OPERACAO_INTERSECAO){
		    			acumulador =  validacaoA &&
		    			validacaoB;
	    			}
	    			if(operacaoAB==OPERACAO_UNIAO){
		    			acumulador =  validacaoA ||
		    			validacaoB;
	    			}
	    			
	    			if(operacaoBC==OPERACAO_INTERSECAO){
		    			acumulador = acumulador &&  validacaoC;
	    			}
	    			if(operacaoBC==OPERACAO_UNIAO){
		    			acumulador =  acumulador || validacaoC;
	    			}
    			}else{
    				if(operacaoBC==OPERACAO_INTERSECAO){
		    			acumulador = acumulador &&  validacaoC;
	    			}
	    			if(operacaoBC==OPERACAO_UNIAO){
		    			acumulador =  acumulador || validacaoC;
	    			}
	    			
	    			if(operacaoAB==OPERACAO_INTERSECAO){
		    			acumulador =  validacaoA &&
		    			validacaoB;
	    			}
	    			if(operacaoAB==OPERACAO_UNIAO){
		    			acumulador =  validacaoA ||
		    			validacaoB;
	    			}
    			}
    			
    			return acumulador;
			}
    		
    	});  
		
	}
	
}

